package Test;

import static org.junit.Assert.*;

import java.util.LinkedList;
import java.util.Stack;

import org.junit.Test;

import borderPatrol.Data.Board;
import borderPatrol.Data.Move;
import borderPatrol.Data.PatrollerBoard;
import borderPatrol.Data.PoacherBoard;
import borderPatrol.misc.History;

public class BoardTest {

	@Test
	public void makeMoveBeforeEndTurnTest() {

		Board board = new PoacherBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		assertEquals(-1, board.getPosition()[0]);
		assertEquals(-1, board.getPosition()[1]);
		assertEquals("1", board.getId());
	}

	@Test
	public void makeMoveBeforeEndTurnTestWithoutCompleteMoves() {

		Board board = new PoacherBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);

		board.endTurn();

		assertEquals(-1, board.getPosition()[0]);
		assertEquals(-1, board.getPosition()[1]);
		assertEquals("1", board.getId());
	}

	@Test
	public void makeMoveAndEndTurnTestForPoacher() {

		Board board = new PoacherBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();

		assertEquals(0, board.getPosition()[0]);
		assertEquals(1, board.getPosition()[1]);
		assertEquals("1.01", board.getId());
	}

	@Test
	public void makeMoveAndEndTurnTestForPatroller() {

		Board board = new PatrollerBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();

		assertEquals(2, board.getPosition()[0]);
		assertEquals(1, board.getPosition()[1]);
		assertEquals("2.21", board.getId());
	}

	@Test
	public void availableActionsTestForPatrollerOnBeginning() {

		Board board = new PatrollerBoard(3, 3);

		assertEquals(3, board.getAvailableActions().size());
		assertEquals(true, board.getAvailableActions().contains(new Move(2, 0)));
		assertEquals(true, board.getAvailableActions().contains(new Move(2, 1)));
		assertEquals(true, board.getAvailableActions().contains(new Move(2, 2)));
	}

	@Test
	public void availableActionsTestForPoacherOnBeginning() {

		Board board = new PoacherBoard(3, 3);

		assertEquals(3, board.getAvailableActions().size());
		assertEquals(true, board.getAvailableActions().contains(new Move(0, 0)));
		assertEquals(true, board.getAvailableActions().contains(new Move(0, 1)));
		assertEquals(true, board.getAvailableActions().contains(new Move(0, 2)));
	}

	@Test
	public void availableActionsTestForPoacher() {

		Board board = new PoacherBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();

		assertEquals(3, board.getAvailableActions().size());
		assertEquals(true, board.getAvailableActions().contains(new Move(0, 0)));
		assertEquals(true, board.getAvailableActions().contains(new Move(1, 1)));
		assertEquals(true, board.getAvailableActions().contains(new Move(0, 2)));
	}

	@Test
	public void availableActionsTestForPoacherOne() {

		Board board = new PoacherBoard(3, 3);

		board.makeMove(new Move(0, 0), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();

		assertEquals(2, board.getAvailableActions().size());
		assertEquals(true, board.getAvailableActions().contains(new Move(1, 0)));
		assertEquals(true, board.getAvailableActions().contains(new Move(0, 1)));
	}

	@Test
	public void availableActionsTestForPoacherTwo() {

		Board board = new PoacherBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 1), 1);
		board.makeMove(new Move(2, 0), 2);

		board.endTurn();

		assertEquals(3, board.getAvailableActions().size());
		assertEquals(true, board.getAvailableActions().contains(new Move(1, 2)));
		assertEquals(true, board.getAvailableActions().contains(new Move(1, 0)));
		assertEquals(true, board.getAvailableActions().contains(new Move(2, 1)));
	}
	
	@Test
	public void availableActionsTestForPatroller() {

		Board board = new PatrollerBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();

		assertEquals(3, board.getAvailableActions().size());
		assertEquals(true, board.getAvailableActions().contains(new Move(2, 0)));
		assertEquals(true, board.getAvailableActions().contains(new Move(1, 1)));
		assertEquals(true, board.getAvailableActions().contains(new Move(2, 2)));
	}

	@Test
	public void availableActionsTestForPatrollerOne() {

		Board board = new PatrollerBoard(3, 3);

		board.makeMove(new Move(0, 0), 1);
		board.makeMove(new Move(2, 0), 2);

		board.endTurn();

		assertEquals(2, board.getAvailableActions().size());
		assertEquals(true, board.getAvailableActions().contains(new Move(1, 0)));
		assertEquals(true, board.getAvailableActions().contains(new Move(2, 1)));
	}

	@Test
	public void availableActionsTestForPatrollerTwo() {

		Board board = new PatrollerBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		board.makeMove(new Move(0, 2), 1);
		board.makeMove(new Move(1, 1), 2);

		board.endTurn();

		assertEquals(4, board.getAvailableActions().size());
		assertEquals(true, board.getAvailableActions().contains(new Move(1, 2)));
		assertEquals(true, board.getAvailableActions().contains(new Move(1, 0)));
		assertEquals(true, board.getAvailableActions().contains(new Move(2, 1)));
		assertEquals(true, board.getAvailableActions().contains(new Move(0, 1)));
	}
	
	@Test
	public void isTerminalTestWithTwoExpected() {

		Board board = new PatrollerBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 1), 1);
		board.makeMove(new Move(1, 1), 2);

		board.endTurn();

		assertEquals(2, board.isTerminal());
	}
	
	@Test
	public void isTerminalTestWithOneExpected() {

		Board board = new PatrollerBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 1), 1);
		board.makeMove(new Move(2, 2), 2);

		board.endTurn();
		
		board.makeMove(new Move(2, 1), 1);
		board.makeMove(new Move(1, 2), 2);

		board.endTurn();
		
		board.makeMove(new Move(3, 3), 1);
		board.makeMove(new Move(2, 2), 2);

		board.endTurn();

		assertEquals(1, board.isTerminal());
	}
	
	@Test
	public void isTerminalTestWithZeroExpected() {

		Board board = new PatrollerBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 1), 1);
		board.makeMove(new Move(2, 2), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 0), 1);
		board.makeMove(new Move(1, 2), 2);

		board.endTurn();

		assertEquals(0, board.isTerminal());
	}
	
	@Test
	public void isTerminalTestWithZeroExpectedOne() {

		Board board = new PatrollerBoard(3, 3);


		assertEquals(0, board.isTerminal());
	}
	
	@Test
	public void isTerminalTestWithCollisionOnEdge() {

		Board board = new PatrollerBoard(3, 3);

		board.makeMove(new Move(0, 0), 1);
		board.makeMove(new Move(2, 1), 2);
		
		board.endTurn();
		
		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(1, 1), 2);
		
		board.endTurn();
		
		board.makeMove(new Move(1, 1), 1);
		board.makeMove(new Move(0, 1), 2);
		
		board.endTurn();
		
		assertEquals(2, board.isTerminal());
	}
	
	@Test
	public void isTerminalTestWithCollisionOnEdgeOne() {

		Board board = new Board(3, 3, new Stack<int[][]>(), new int[]{0, 1}, new int[]{1, 1}, 2, "", "", "", new LinkedList<History>(), new LinkedList<History>());

		board.makeMove(new Move(1, 1), 1);
		board.makeMove(new Move(0, 1), 2);
		
		board.endTurn();
		
		assertEquals(2, board.isTerminal());
		assertEquals(2, board.clone().isTerminal());
		assertEquals(-1, board.getGainForPlayer((byte) 1), 0.00001);
	}
	
	@Test
	public void isTerminalTestWithRoundLimitExceeded() {

		Board board = new Board(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);
		
		board.endTurn();
		
		board.makeMove(new Move(0, 0), 1);
		board.makeMove(new Move(2, 0), 2);
		
		board.endTurn();
		
		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);
		
		board.endTurn();
		
		board.makeMove(new Move(0, 0), 1);
		board.makeMove(new Move(2, 0), 2);
		
		board.endTurn();
		
		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);
		
		board.endTurn();
		
		board.makeMove(new Move(0, 0), 1);
		board.makeMove(new Move(2, 0), 2);
		
		board.endTurn();
		
		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);
		
		board.endTurn();
		
		assertEquals(2, board.isTerminal());
		assertEquals(2, board.clone().isTerminal());
		assertEquals(-1, board.getGainForPlayer((byte) 1), 0.00001);
	}
	
	@Test
	public void reverseTest() {

		Board board = new PatrollerBoard(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 1), 1);
		board.makeMove(new Move(2, 2), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 0), 1);
		board.makeMove(new Move(1, 2), 2);

		board.endTurn();

		board.undoLastTurn();
		
		assertEquals(2, board.getPosition()[0]);
		assertEquals(2, board.getPosition()[1]);
		assertEquals("2.21.22", board.getId());
	}
	
	@Test
	public void reverseTestOne() {

		Board board = new Board(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 1), 1);
		board.makeMove(new Move(2, 2), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 0), 1);
		board.makeMove(new Move(1, 2), 2);

		board.endTurn();

		board.undoLastTurn();

		assertEquals(".01.21.11.22", board.getId());
	}
	
	@Test
	public void opponentPositionsTest() {

		Board board = new Board(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 1), 1);
		board.makeMove(new Move(2, 2), 2);

		board.endTurn();
		
		board.makeMove(new Move(1, 0), 1);
		board.makeMove(new Move(1, 2), 2);

		board.endTurn();
		
		assertEquals(8, board.getPossiblePositionsOfOpponent(1).size());
		assertEquals(5, board.getPossiblePositionsOfOpponent(2).size());
	}
	
	@Test
	public void opponentPositionsTestInFirstRound() {

		Board board = new Board(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		assertEquals(3, board.getPossiblePositionsOfOpponent(1).size());
		assertEquals(3, board.getPossiblePositionsOfOpponent(2).size());
	}
	
	@Test
	public void opponentPositionsTestInSecondRound() {

		Board board = new Board(3, 3);

		board.makeMove(new Move(0, 1), 1);
		board.makeMove(new Move(2, 1), 2);

		board.endTurn();
		
		assertEquals(3, board.getPossiblePositionsOfOpponent(1).size());
		assertEquals(3, board.getPossiblePositionsOfOpponent(2).size());
	}
	
//	@Test
//	public void possibleHistoriesTest() {
//
//		Board board = new Board(3, 3);
//
//		board.makeMove(new Move(0, 1), 1);
//		board.makeMove(new Move(2, 0), 2);
//
//		board.endTurn();
//		
//		board.makeMove(new Move(1, 1), 1);
//		board.makeMove(new Move(1, 0), 2);
//
//		board.endTurn();
//		
//		board.makeMove(new Move(1, 0), 1);
//		board.makeMove(new Move(2, 0), 2);
//
//		board.endTurn();
//		
//		board.makeMove(new Move(1, 1), 1);
//		board.makeMove(new Move(2, 1), 2);
//
//		board.endTurn();
//	}

}
